/***************************************************************************
 *   oboe.utils.HSLA                                                       *
 *   Copyright (C) 2011 by Felipe Manga                                    *
 *   lufeboma@gmail.com                                                    *
 *                                                                         *
 *   Permission is hereby granted, free of charge, to any person obtaining *
 *   a copy of this software and associated documentation files (the       *
 *   "Software"), to deal in the Software without restriction, including   *
 *   without limitation the rights to use, copy, modify, merge, publish,   *
 *   distribute, sublicense, and/or sell copies of the Software, and to    *
 *   permit persons to whom the Software is furnished to do so, subject to *
 *   the following conditions:                                             *
 *                                                                         *
 *   The above copyright notice and this permission notice shall be        *
 *   included in all copies or substantial portions of the Software.       *
 *                                                                         *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       *
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    *
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR     *
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
 *   OTHER DEALINGS IN THE SOFTWARE.                                       *
 ***************************************************************************/

package oboe.utils
{
	import flash.display.BitmapData;
	import flash.geom.Rectangle;
	import flash.utils.ByteArray;
	import flash.utils.Endian;
	public class HSLA
	{
		public var h : Number;
		public var s : Number;
		public var l : Number;
		public var a : Number;
		
		public function toString() : String {
			return "H: " + h + ", S: " + s + ", L:" + l + ", A:" + a;
		}
		
		public static const LUMINANCE : uint = 1;
		public static const SATURATION : uint = 2;
		public static const HUE : uint = 4;
		public static const ALL : uint = 7;
		
		public function HSLA() { }
		
		public function toARGB() : uint {
			var r : Number, g : Number, b : Number;
			if ( s == 0 ) {
				r = g = b = l;
			}else {
				var t2 : Number;
				if ( l < 0.5 ) t2 = l * (1.0 + s);
				else t2 = l + s - l * s;
				var t1 : Number = 2.0 * l - t2;

				var t3 : Number = h + 1.0 / 3.0;
				if ( t3 < 0 ) t3++;
				else if ( t3 > 1 ) t3--;
				if ( t3 * 6.0 < 1 ) r = t1 + (t2 - t1) * 6.0 * t3;
				else if ( t3 * 2.0 < 1 ) r = t2;
				else if ( t3 * 3.0 < 2 ) r = t1 + (t2 - t1) * ((2.0 / 3.0) - t3) * 6.0;
				else r = t1;

				t3 = h;
				if ( t3 < 0 ) t3++;
				else if ( t3 > 1 ) t3--;
				if ( t3 * 6.0 < 1 ) g = t1 + (t2 - t1) * 6.0 * t3;
				else if ( t3 * 2.0 < 1 ) g = t2;
				else if ( t3 * 3.0 < 2 ) g = t1 + (t2 - t1) * ((2.0 / 3.0) - t3) * 6.0;
				else g = t1;
				
				t3 = h - 1.0 / 3.0;
				if ( t3 < 0 ) t3++;
				else if ( t3 > 1 ) t3--;
				if ( t3 * 6.0 < 1 ) b = t1 + (t2 - t1) * 6.0 * t3;
				else if ( t3 * 2.0 < 1 ) b = t2;
				else if ( t3 * 3.0 < 2 ) b = t1 + (t2 - t1) * ((2.0 / 3.0) - t3) * 6.0;
				else b = t1;
			}
			return (uint(a*255.0)<<24) + (uint(r*255.0)<<16) + (uint(g*255.0)<<8) + uint(b*255.0);
		}
		
		public static function colorBitmapU32( bd : BitmapData, rgb : uint , scaleLum : Boolean, reference:uint = 0 ) : void {
			colorBitmap( bd, (rgb>>16)&0xFF, (rgb>>8)&0xFF, rgb&0xFF, scaleLum, reference );
		}

		public static function colorBitmap( bd : BitmapData, r : uint, g : uint, b : uint, scaleLum : Boolean, reference : uint = 0 ) : void {
			var target : HSLA = fromARGB( 0xFF, r, g, b );
			var rect : Rectangle = new Rectangle(0, 0, bd.width, bd.height);
			var inp : ByteArray = bd.getPixels( rect );
			var out : ByteArray = new ByteArray();
			var cur : HSLA;
			var u : uint;
			out.length = inp.length;
			out.endian = Endian.LITTLE_ENDIAN;
			inp.position = 0;
			var ref : HSLA;
			if( !reference ) ref = fromU32( inp.readUnsignedInt(), LUMINANCE + HUE );
			else ref = fromU32( reference, LUMINANCE + HUE );
			target.l = (target.l * 0.8) / ref.l;
			inp.position = 0;
			out.position = 0;
			if( scaleLum ){
				while ( inp.position != inp.length ) {
					cur = fromU32( inp.readUnsignedInt() );
					if( cur.s )
					{
						cur.l *= target.l;
						if ( cur.l > 1 ) cur.l = 1;
						cur.h += target.h - ref.h;
						// cur.s = target.s/ref.s;
						if ( cur.h < 0 ) cur.h++;
						else if ( cur.h > 1 ) cur.h--;
						out.writeUnsignedInt(cur.toARGB());
					}
				}
			}else {
				while ( inp.position != inp.length ) {
					cur = fromU32( inp.readUnsignedInt() );
					if( cur.s )
					{
						cur.h += target.h - ref.h;
						// cur.s = target.s - ref.s;
						
						if ( cur.h < 0 ) cur.h++;
						else if ( cur.h > 1 ) cur.h--;
						out.writeUnsignedInt(cur.toARGB());
					}
				}
			}
			out.position = 0;
			bd.setPixels( rect, out );
		}
		
		public static function getLuma( r : uint, g : uint, b : uint ) : Number {
			var max : Number = r;
			var min : Number = g;
			if ( g > r ) {
				max = g;
				min = r;
			}
			if ( b > max ) 	max = b;
			else if ( b < min ) min = b;
			return (max + min) / 2;
		} 
		
		public static function fromU32( u : uint, components : uint = ALL ) : HSLA {
			return fromARGB( u>>24, u>>16, u>>8, u, components  );
		}
		public static function fromARGB( a : uint, r : uint, g : uint, b : uint, components : uint = ALL ) : HSLA {
			return fromNormalizedARGB( (a&0xFF)/255.0, (r&0xFF)/255.0, (g&0xFF)/255.0, (b&0xFF)/255.0, components );
		}
		public static function fromNormalizedARGB( a : Number, r : Number, g : Number, b : Number, components : uint = ALL ) : HSLA {
			var hsl : HSLA = new HSLA();
			hsl.s = hsl.h = 0;
			if ( components == 0 ) return hsl;
			hsl.a = a;
			var max : Number = r;
			var min : Number = g;
			if ( g > r ) {
				max = g;
				min = r;
			}
			if ( b > max ) 	max = b;
			else if ( b < min ) min = b;
			var mmd : Number = max - min;
			
			hsl.l = (max + min) / 2;
			if ( max == min || components == LUMINANCE ) return hsl;
			if ( (components & SATURATION) != 0 ){
				if ( hsl.l < 0.5 ) hsl.s = mmd / (max + min);
				else hsl.s = mmd / (2.0 - mmd);
			}
			if ( (components & HUE) != 0 ){
				if ( r == max ) hsl.h = (g - b) / mmd;
				else if ( g == max ) hsl.h = 2.0 + (b - r) / mmd;
				else hsl.h = 4.0 + (r - g) / mmd;
				hsl.h /= 6.0;
				if ( hsl.h < 0 ) hsl.h++;
			}
			return hsl;
		}
	}

}